package com.learn.concurrent;

import org.openjdk.jol.info.ClassLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.LocalTime;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @author wangxing
 * @version 2020/8/3 8:40 Administrator
 */
public class LearnSynchronized {
    static Logger logger = LoggerFactory.getLogger(LearnSynchronized.class);
    private int count =10;
    private final Object o = new Object();
    public static void main(String[] args){
//        executorsLearn();
        runNoStaticMethodNewObject();
        runNoStaticMethodThis();
        runNoStaticMethodClass();
        runNoStaticMethodClass2();
        runNoStaticMethodClass3();
        runSynchronizedMethodNoStatic();
        runSynchronizedMethodStatic();
    }

    //    锁升级过程内部对象头变化
    public static void noLock(){

        Object a = new Object();
        System.out.println(ClassLayout.parseInstance(a).toPrintable());
        synchronized (a) {
            System.out.println(ClassLayout.parseInstance(a).toPrintable());
        }
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        for (int i = 0; i < 2; i++) {
            executorService.execute(()->{
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(ClassLayout.parseInstance(a).toPrintable());
            });
        }
        executorService.shutdown();
    }

    /**
     * 线程池使用
     * @throws InterruptedException
     */
    public static void executorsLearn() throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        LearnSynchronized learnSynchronized = new LearnSynchronized();
        for (int i = 0; i <10 ; i++) {
            Thread thread =new Thread(learnSynchronized::m,"thread"+i);
            executorService.execute(thread);
            thread.join();
        }
//        一定要释放线程池
        executorService.shutdown();
        System.out.println("-------"+learnSynchronized.count);

    }
    public void m(){
        synchronized (o){
            count--;
            System.out.println(Thread.currentThread().getName()+" count = "+count);
        }
    }

    /**
     * 临时抽取相同输出内容方法
     * @param now 当前线程
     */
    public static void  tempSleep2PrintMessage(Thread now){
        try {
            logger.info("run start threadName is {};methodName is {};time is {};", now.getName(),now.getStackTrace()[3].getMethodName(), LocalTime.now());
            TimeUnit.SECONDS.sleep(2);
            logger.info("run end threadName is {};methodName is {};time is {};", now.getName(),now.getStackTrace()[3].getMethodName(), LocalTime.now());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 对象锁 1 每次用新对象作为锁
     */
    public void synchronizedNoStaticMethodNewObject(){
        Thread now = Thread.currentThread();
        logger.info("into threadName is {};methodName is {};time is {};", now.getName(),now.getStackTrace()[2].getMethodName(), LocalTime.now());
        synchronized (new Object()){
            tempSleep2PrintMessage(now);
        }
    }

    /**
     * 每个对象的方法都是独立的不会锁定
     * 四个线程同时开始，同时结束，因为作为锁的对象与线程是属于不同的实例。
     */
    public static void runNoStaticMethodNewObject(){
        LearnSynchronized learnSynchronized = new LearnSynchronized();
        Thread t1 = new Thread(learnSynchronized::synchronizedNoStaticMethodNewObject,"t1Thread");
        Thread t2 = new Thread(learnSynchronized::synchronizedNoStaticMethodNewObject,"t2Thread");
        Thread t3 = new Thread(()-> new LearnSynchronized().synchronizedNoStaticMethodNewObject(),"t3Thread");
        Thread t4 = new Thread(()-> new LearnSynchronized().synchronizedNoStaticMethodNewObject(),"t4Thread");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }

    /**
     * 对象锁 2 使用this作为锁
     */
    public void synchronizedNoStaticMethodThis(){
        Thread now = Thread.currentThread();
        logger.info("into threadName is {};methodName is {};time is {};", now.getName(),now.getStackTrace()[2].getMethodName(), LocalTime.now());
        synchronized (this){
            tempSleep2PrintMessage(now);
        }
    }

    /**
     * 会锁定同一个对象对应的方法
     * 不会锁定不同对象的方法
     */
    public static void runNoStaticMethodThis(){
        LearnSynchronized learnSynchronized = new LearnSynchronized();
        Thread t1 = new Thread(learnSynchronized::synchronizedNoStaticMethodThis,"t1Thread");
        Thread t2 = new Thread(learnSynchronized::synchronizedNoStaticMethodThis,"t2Thread");
        Thread t3 = new Thread(()-> new LearnSynchronized().synchronizedNoStaticMethodThis(),"t3Thread");
        Thread t4 = new Thread(()-> new LearnSynchronized().synchronizedNoStaticMethodThis(),"t4Thread");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }

    /**
     * 类锁 使用类对象作为锁
     */
    public void synchronizedNoStaticMethodClass(){
        Thread now = Thread.currentThread();
        logger.info("into threadName is {};methodName is {};time is {};", now.getName(),now.getStackTrace()[2].getMethodName(), LocalTime.now());
        synchronized (LearnSynchronized.class){
            tempSleep2PrintMessage(now);
        }
    }
    public void synchronizedNoStaticMethodClass2(){
        Thread now = Thread.currentThread();
        logger.info("into threadName is {};methodName is {};time is {};", now.getName(),now.getStackTrace()[2].getMethodName(), LocalTime.now());
        synchronized (Object.class){
            tempSleep2PrintMessage(now);
        }
    }
    public void synchronizedNoStaticMethodClass3(){
        Thread now = Thread.currentThread();
        logger.info("into threadName is {};methodName is {};time is {};", now.getName(),now.getStackTrace()[2].getMethodName(), LocalTime.now());
        synchronized (Object.class){
            tempSleep2PrintMessage(now);
        }
    }
    /**
     * 采用类锁一次只能通过一个线程去进行执行
     */
    public static void runNoStaticMethodClass(){
        LearnSynchronized learnSynchronized = new LearnSynchronized();
        Thread t1 = new Thread(learnSynchronized::synchronizedNoStaticMethodClass,"t1Thread");
        Thread t2 = new Thread(learnSynchronized::synchronizedNoStaticMethodClass,"t2Thread");
        Thread t3 = new Thread(()-> new LearnSynchronized().synchronizedNoStaticMethodClass(),"t3Thread");
        Thread t4 = new Thread(()-> new LearnSynchronized().synchronizedNoStaticMethodClass(),"t4Thread");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
    /**
     * 采用同一个类进行类锁,不同的方法也会被同时锁定
     */
    public static void runNoStaticMethodClass2(){
        LearnSynchronized learnSynchronized = new LearnSynchronized();
        Thread t1 = new Thread(learnSynchronized::synchronizedNoStaticMethodClass2,"t1Thread");
        Thread t2 = new Thread(learnSynchronized::synchronizedNoStaticMethodClass2,"t2Thread");
        Thread t3 = new Thread(()-> new LearnSynchronized().synchronizedNoStaticMethodClass3(),"t3Thread");
        Thread t4 = new Thread(()-> new LearnSynchronized().synchronizedNoStaticMethodClass3(),"t4Thread");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
    /**
     * 采用不同的类锁,相互不同方法锁的方法不会产生影响
     */
    public static void runNoStaticMethodClass3(){
        LearnSynchronized learnSynchronized = new LearnSynchronized();
        Thread t1 = new Thread(learnSynchronized::synchronizedNoStaticMethodClass,"t1Thread");
        Thread t2 = new Thread(learnSynchronized::synchronizedNoStaticMethodClass,"t2Thread");
        Thread t3 = new Thread(()-> new LearnSynchronized().synchronizedNoStaticMethodClass2(),"t3Thread");
        Thread t4 = new Thread(()-> new LearnSynchronized().synchronizedNoStaticMethodClass2(),"t4Thread");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }

    /**
     * synchronized修饰方法
     */
    public synchronized void synchronizedMethodNoStatic(){
        Thread now = Thread.currentThread();
        logger.info("into threadName is {};methodName is {};time is {};", now.getName(),now.getStackTrace()[2].getMethodName(), LocalTime.now());
        tempSleep2PrintMessage(now);
    }

    /**
     * 对于synchronized修饰非静态方法，同一个实例的线程访问会被拦截，非同一实例可以同时访问。 等同于对象锁
     */
    public static void runSynchronizedMethodNoStatic(){
        LearnSynchronized learnSynchronized = new LearnSynchronized();
        Thread t1 = new Thread(learnSynchronized::synchronizedMethodNoStatic,"t1Thread");
        Thread t2 = new Thread(learnSynchronized::synchronizedMethodNoStatic,"t2Thread");
        Thread t3 = new Thread(()-> new LearnSynchronized().synchronizedMethodNoStatic(),"t3Thread");
        Thread t4 = new Thread(()-> new LearnSynchronized().synchronizedMethodNoStatic(),"t4Thread");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
    /**
     * synchronized修饰静态方法
     */
    public static synchronized void synchronizedMethodStatic(){
        Thread now = Thread.currentThread();
        logger.info("into threadName is {};methodName is {};time is {};", now.getName(),now.getStackTrace()[2].getMethodName(), LocalTime.now());
        tempSleep2PrintMessage(now);
    }
    /**
     * 对于synchronized修饰静态方法,是一个接一个去执行的,等同于类锁
     */
    public static void runSynchronizedMethodStatic(){
        Thread t1 = new Thread(LearnSynchronized::synchronizedMethodStatic,"t1Thread");
        Thread t2 = new Thread(LearnSynchronized::synchronizedMethodStatic,"t2Thread");
        Thread t3 = new Thread(LearnSynchronized::synchronizedMethodStatic,"t3Thread");
        Thread t4 = new Thread(LearnSynchronized::synchronizedMethodStatic,"t4Thread");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}
